/**
 * QUANSHI.com Inc.
 * Copyright (c) 2016-2017 All Rights Reserved.
 */
package com.quanshi.scheduler.job.biz.service.impl;

import java.text.MessageFormat;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import javax.annotation.Resource;

import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.math.NumberUtils;
import org.quartz.SchedulerException;
import org.springframework.stereotype.Service;
import org.springframework.util.Assert;

import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import com.google.common.collect.Lists;
import com.quanshi.scheduler.core.base.Ret;
import com.quanshi.scheduler.job.biz.mapper.JobInfoMapper;
import com.quanshi.scheduler.job.biz.model.req.TriggerInfoReq;
import com.quanshi.scheduler.job.biz.model.vo.TriggerInfoVO;
import com.quanshi.scheduler.job.biz.quartz.JobDynamicScheduler;
import com.quanshi.scheduler.job.biz.service.BaseService;
import com.quanshi.scheduler.job.biz.service.TriggerInfoService;
import com.quanshi.scheduler.job.dal.dao.TriggerInfoMapper;
import com.quanshi.scheduler.job.dal.entity.TriggerInfo;
import com.quanshi.scheduler.job.dal.entity.TriggerInfoExample;
import com.quanshi.scheduler.job.dal.entity.TriggerInfoExample.Criteria;

/**
 * 
 * @author yanxiang.huang 2017-07-11 09:02:58
 */
@Service
public class TriggerInfoServiceImpl extends BaseService implements TriggerInfoService {

    @Resource
    private TriggerInfoMapper mapper;

    @Override
    public TriggerInfo get(long id) {
        TriggerInfo info = mapper.selectByPrimaryKey(id);
        return info;
    }

    @Override
    public boolean save(TriggerInfo jobInfo) {
        Assert.notNull(jobInfo, "job info can't be null.");
        Date now = new Date();
        jobInfo.setAddTime(now);
        jobInfo.setUpdateTime(now);
        jobInfo.setGlueUpdatetime(now);

        int res = mapper.insert(jobInfo);
        if (res == 1) {
            return true;
        }
        return false;
    }

    @Override
    public void delete(Long id) {
        Assert.notNull(id, "id can't be null.");
        mapper.deleteByPrimaryKey(id);
    }

    @Override
    public long findAllCount() {
        TriggerInfoExample query = new TriggerInfoExample();
        return mapper.countByExample(query);
    }

    @Override
    public Ret<PageInfo<TriggerInfoVO>> findPage(TriggerInfoReq req) {
        Assert.notNull(req, "req can't be null.");
        TriggerInfoExample query = createQuery(req);
        if (req.getPageNo() > 0 && req.getPageSize() > 0) {
            PageHelper.startPage(req.getPageNo(), req.getPageSize());
        } else {
            PageHelper.startPage(1, 10);
        }
        List<TriggerInfo> datas = mapper.selectByExample(query);
        if (CollectionUtils.isNotEmpty(datas)) {
            List<TriggerInfoVO> list = Lists.newArrayList();
            for (TriggerInfo o : datas) {
                TriggerInfoVO vo = JobInfoMapper.do2vo(o);
                JobDynamicScheduler.fillJobInfo(vo);
                list.add(vo);
            }
            PageInfo<TriggerInfoVO> page = new PageInfo<>(list);
            PageHelper.clearPage();
            return new Ret<PageInfo<TriggerInfoVO>>(page);
        }
        return new Ret<PageInfo<TriggerInfoVO>>(null);
    }

    @Override
    public Map<String, Object> findPageList(TriggerInfoReq req) {
        Assert.notNull(req, "req can't be null.");
        TriggerInfoExample query = createQuery(req);
        if (req.getStart() >= 0 && req.getLength() > 0) {
            PageHelper.offsetPage(req.getStart(), req.getLength());
        } else {
            PageHelper.offsetPage(0, 10);
        }
        List<TriggerInfo> datas = mapper.selectByExample(query);
        long total = mapper.countByExample(query);
        PageHelper.clearPage();
        List<TriggerInfoVO> list = Lists.newArrayList();
        if (CollectionUtils.isNotEmpty(datas)) {
            for (TriggerInfo o : datas) {
                TriggerInfoVO vo = JobInfoMapper.do2vo(o);
                JobDynamicScheduler.fillJobInfo(vo);
                list.add(vo);
            }
        }
        Map<String, Object> maps = new HashMap<String, Object>();
        maps.put("recordsTotal", total); // 总记录数
        maps.put("recordsFiltered", total); // 过滤后的总记录数
        maps.put("data", list);
        return maps;
    }

    @Override
    public boolean update(TriggerInfo jobInfo) {
        Assert.notNull(jobInfo, "jobInfo can't be null.");
        Assert.notNull(jobInfo.getId(), "jobInfo id can't be null.");
        TriggerInfo old = get(jobInfo.getId());
        if (old == null) {
            logger.info("can't find job info by id:{}.", jobInfo.getId());
            return false;
        }
        jobInfo.setJobGroup(old.getJobGroup());
        jobInfo.setGlueType(old.getGlueType());

        old.setJobCron(jobInfo.getJobCron());
        old.setJobDesc(jobInfo.getJobDesc());
        old.setAuthor(jobInfo.getAuthor());
        old.setAlarmEmail(jobInfo.getAlarmEmail());
        old.setExecutorRouteStrategy(jobInfo.getExecutorRouteStrategy());
        old.setExecutorHandler(jobInfo.getExecutorHandler());
        old.setExecutorParam(jobInfo.getExecutorParam());
        old.setExecutorBlockStrategy(jobInfo.getExecutorBlockStrategy());
        old.setExecutorFailStrategy(jobInfo.getExecutorFailStrategy());
        old.setChildJobkey(jobInfo.getChildJobkey());
        old.setUpdateTime(new Date());
        int res = mapper.updateByPrimaryKey(old);
        if (res == 1) {
            return true;
        }
        return false;
    }

    @Override
    public boolean updateGlue(TriggerInfo jobInfo) {
        Assert.notNull(jobInfo, "jobInfo can't be null.");
        Assert.notNull(jobInfo.getId(), "jobInfo id can't be null.");
        TriggerInfo old = get(jobInfo.getId());
        if (old == null) {
            logger.info("can't find job info by id:{}.", jobInfo.getId());
            return false;
        }
        old.setGlueUpdatetime(new Date());
        old.setGlueRemark(jobInfo.getGlueRemark());
        old.setGlueSource(jobInfo.getGlueSource());
        int res = mapper.updateByPrimaryKeyWithBLOBs(old);
        if (res == 1) {
            return true;
        }
        return false;
    }

    @Override
    public boolean checkHasUse(long groupId) {
        TriggerInfoExample query = new TriggerInfoExample();
        query.createCriteria().andJobGroupEqualTo(groupId);
        long count = mapper.countByExample(query);
        if (count > 0) {
            return true;
        }
        return false;
    }

    @Override
    public List<TriggerInfoVO> getByGroup(Long groupId) {
        TriggerInfoExample query = new TriggerInfoExample();
        query.createCriteria().andJobGroupEqualTo(groupId);
        List<TriggerInfo> datas = mapper.selectByExample(query);
        List<TriggerInfoVO> list = Lists.newArrayList();
        if (CollectionUtils.isNotEmpty(datas)) {
            for (TriggerInfo o : datas) {
                TriggerInfoVO vo = JobInfoMapper.do2vo(o);
                // JobDynamicScheduler.fillJobInfo( vo );
                list.add(vo);
            }
        }
        return list;
    }

    @Override
    public String triggerChild(Long id) {
        String msg = "";
        TriggerInfo job = get(id);
        if (job == null || StringUtils.isBlank(job.getChildJobkey())) {
            return msg;
        }
        String[] childJobKeys = StringUtils.split(job.getChildJobkey(), ",");
        for (String childJobKey : childJobKeys) {
            String[] jobKeys = childJobKey.split("_");
            if (jobKeys.length == 2) {
                String childId = jobKeys[1];
                long cid = NumberUtils.toLong(childId);
                TriggerInfo child = get(cid);
                if (child != null) {
                    try {
                        boolean res = JobDynamicScheduler.triggerJob(child.getId().toString(), child.getJobGroup().toString());
                        if (res) {
                            msg += MessageFormat.format("<br> 触发子任务成功, 子任务Key: {0}, status: {1}, 子任务描述: {2}", childJobKey, res, child.getJobDesc());
                        } else {
                            msg += MessageFormat.format("<br> 触发子任务失败, 子任务Key: {0}, status: {1}, 子任务描述: {2}", childJobKey, res, child.getJobDesc());
                        }
                    } catch (SchedulerException e) {
                        msg += MessageFormat.format("<br> 触发子任务失败, 子任务Key: {0}, 子任务描述: {1}", childJobKey, child.getJobDesc());
                    }
                } else {
                    msg += MessageFormat.format("<br> 触发子任务失败, 子任务Key: {0}, 子任务不存在.", childJobKey);
                }
            } else {
                msg += MessageFormat.format("<br> 触发子任务失败, 子任务Key格式错误, 子任务Key: {0}", childJobKey);
            }
        }
        return msg;
    }

    /**
     * 创建查询体
     *
     * @param req
     * @return
     */
    private TriggerInfoExample createQuery(TriggerInfoReq req) {
        TriggerInfoExample query = new TriggerInfoExample();
        Criteria c = query.createCriteria();
        if (req.getJobGroup() != null && req.getJobGroup() > 0) {
            c.andJobGroupEqualTo(req.getJobGroup());
        }
        if (StringUtils.isNotBlank(req.getAuthor())) {
            c.andAuthorEqualTo(req.getAuthor());
        }
        if (StringUtils.isNotBlank(req.getGlueType())) {
            c.andGlueTypeEqualTo(req.getGlueType());
        }
        if (StringUtils.isNotBlank(req.getExecutorHandler())) {
            c.andExecutorHandlerEqualTo(req.getExecutorHandler());
        }
        if (StringUtils.isNotBlank(req.getExecutorBlockStrategy())) {
            c.andExecutorBlockStrategyEqualTo(req.getExecutorBlockStrategy());
        }
        if (StringUtils.isNotBlank(req.getExecutorFailStrategy())) {
            c.andExecutorFailStrategyEqualTo(req.getExecutorFailStrategy());
        }
        if (StringUtils.isNotBlank(req.getExecutorRouteStrategy())) {
            c.andExecutorRouteStrategyEqualTo(req.getExecutorRouteStrategy());
        }
        return query;
    }

}
